using System;
using System.Collections.Generic;
using System.Xml.Serialization;

namespace ElfBinary
{
	[Serializable]

	public class SectionHeader64
	{

		public SectionHeader64()
		{
		}

		[XmlIgnore]
		public ElfBinaryFile Parent{ get; set;}

		public SectionHeader64 (ElfBinaryFile parent )
		{
			Parent = parent;
		}

		byte[] SectionBytes;

		string name=null;

		[XmlElement]
		public string SectionName { 
			get {
		
				if (name != null) {
					return name;
				}
				if (this.sh_name == 0) {
					return string.Empty;
				} else {
					if (SectionType == ElfSectionType.DynamicLinkingInfo ||
					    SectionType == ElfSectionType.DynamicLinkingSymbols ||
					    SectionType == ElfSectionType.SymbolTable) {
						return	Parent.SectionHeaders64 [(int)sh_link].GetString (sh_name);
					} else {
					
						return string.Empty;
					}
				}

			
			}

			set {
				name = value;
			}
		}

	

		[XmlArray("SymbolTable")]
		public List<SymbolTableEntry64> SymbolEntries = new List<SymbolTableEntry64>();

		[XmlElement]
		public ElfSectionType SectionType { 
			get { return (ElfSectionType)sh_type; }
			set { sh_type = (uint)value; }
			
		}

		[XmlElement]
		public ElfSectionAttributeFlags SectionFlags{ 
			get{return (ElfSectionAttributeFlags)sh_flags; }
			set { sh_flags = (ulong)value; }
		}

		[XmlElement]
		public ulong Address { 
			get { return sh_addr; }
			set { sh_addr = value; }
		}

		[XmlElement]
		public ulong Offset { get { return sh_offset; }
			set { sh_offset = value; }
		}

		[XmlElement]
		public ulong Size { 
			get { return sh_size; }
			set { sh_size = value; }
		}

		[XmlElement]
		public uint Link { 
			get { return sh_link; }
			set { sh_link = value; }
		}

		[XmlElement]
		public uint Info { 
			get { return sh_info;}
			set { sh_info = value;}
		}

		[XmlElement]
		public ulong AddressAlign { 
			get { return sh_addralign; }
			set { sh_addralign = value; }
		}

		[XmlElement]
		public ulong EntryItemSize { 
			get { 
				return sh_entsize; }
			set {sh_entsize = value; }
		}

		#region Methods
		public void Read (System.IO.Stream s)
		{

			byte[] b = new byte[8];

			s.Read (b, 0, 4);

			sh_name = BitConverter.ToUInt32 (b, 0);

			s.Read (b, 0, 4);

			sh_type = BitConverter.ToUInt32 (b, 0);

			s.Read (b, 0, 8);

			sh_flags = BitConverter.ToUInt64(b, 0);

			s.Read (b, 0, 8);


			sh_addr = BitConverter.ToUInt64 (b, 0);

			s.Read (b, 0, 8);


			sh_offset = BitConverter.ToUInt64 (b, 0);

			s.Read (b, 0, 8);

			sh_size = BitConverter.ToUInt64 (b, 0);

			s.Read (b, 0, 4);

			sh_link = BitConverter.ToUInt32 (b, 0);

			s.Read (b, 0, 4);


			sh_info = BitConverter.ToUInt32 (b, 0);

			s.Read (b, 0, 8);


			sh_addralign = BitConverter.ToUInt64 (b, 0);

			s.Read (b, 0, 8);


			sh_entsize = BitConverter.ToUInt64 (b, 0);

		}

		public void LoadSectionBytes(System.IO.Stream s)
		{
			s.Seek ((long)this.Offset, System.IO.SeekOrigin.Begin);
			SectionBytes = new byte[this.Size];
			s.Read (SectionBytes, 0, (int)this.Size);

			if (this.SectionType == ElfSectionType.SymbolTable) {
			
				int offset = 0;

				while (offset < SectionBytes.Length)
				{
					SymbolTableEntry64 entry = new SymbolTableEntry64 (this);
					offset = entry.Read (SectionBytes, offset);
					SymbolEntries.Add (entry);
				}
			
			}
		}
	
		public string GetString(long offset)
		{
			if (this.SectionType != ElfSectionType.StringTable) {
			
				throw new Exception ("Invalid Section Type for String Extraction ! Expected: String, Object is: " + this.SectionType.ToString ());

			}

			if (SectionBytes == null) {
		
				throw new NullReferenceException ("You have not yet called LoadSectionBytes !");
				}


			string result = string.Empty;

			long index = offset;

			while (SectionBytes [index] != 0) {
			
				result += (char)SectionBytes [index];
				index++;
				
			}

			return result;

		}

		#endregion 

		#region Fields
		uint	sh_name;
		uint	sh_type;
		ulong	sh_flags;
		ulong	sh_addr;
		ulong	sh_offset;
		ulong	sh_size;
		uint	sh_link;
		uint	sh_info;
		ulong	sh_addralign;
		ulong	sh_entsize;
		#endregion 


	}
}

